home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1991
/
10
/
graphprg.asc
< prev
next >
Wrap
Text File
|
1991-09-10
|
15KB
|
393 lines
_GRAPHICS PROGRAMMING COLUMN_
by Michael Abrash
[LISTING ONE]
/* Demonstrates non-antialiased drawing in 256 color mode. Tested with
Borland C++ 2.0 in C mode in the small model. */
#include <conio.h>
#include <dos.h>
#include "polygon.h"
/* Draws the polygon described by the point list PointList in color
Color with all vertices offset by (X,Y) */
#define DRAW_POLYGON(PointList,Color,X,Y) \
Polygon.Length = sizeof(PointList)/sizeof(struct Point); \
Polygon.PointPtr = PointList; \
FillConvexPolygon(&Polygon, Color, X, Y);
void main(void);
extern int FillConvexPolygon(struct PointListHeader *, int, int, int);
/* Palette RGB settings to load the first four palette locations with
black, pure blue, pure green, and pure red */
static char Palette[4*3] = {0, 0, 0, 0, 0, 63, 0, 63, 0, 63, 0, 0};
void main()
{
struct PointListHeader Polygon;
static struct Point Face0[] =
{{198,138},{211,89},{169,44},{144,89}};
static struct Point Face1[] =
{{153,150},{198,138},{144,89},{105,113}};
static struct Point Face2[] =
{{169,44},{133,73},{105,113},{144,89}};
union REGS regset;
struct SREGS sregs;
/* Set the display to VGA mode 13h, 320x200 256-color mode */
regset.x.ax = 0x0013; int86(0x10, ®set, ®set);
/* Set color 0 to black, color 1 to pure blue, color 2 to pure
green, and color 3 to pure red */
regset.x.ax = 0x1012; /* load palette block BIOS function */
regset.x.bx = 0; /* start with palette register 0 */
regset.x.cx = 4; /* set four palette registers */
regset.x.dx = (unsigned int) Palette;
segread(&sregs);
sregs.es = sregs.ds; /* point ES:DX to Palette */
int86x(0x10, ®set, ®set, &sregs);
/* Draw the cube */
DRAW_POLYGON(Face0, 3, 0, 0);
DRAW_POLYGON(Face1, 2, 0, 0);
DRAW_POLYGON(Face2, 1, 0, 0);
getch(); /* wait for a keypress */
/* Return to text mode and exit */
regset.x.ax = 0x0003; /* AL = 3 selects 80x25 text mode */
int86(0x10, ®set, ®set);
}
[LISTING TWO]
/* Demonstrates unweighted antialiased drawing in 256 color mode.
Tested with Borland C++ 2.0 in C mode in the small model. */
#include <conio.h>
#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include "polygon.h"
/* Draws the polygon described by the point list PointList in color
Color, with all vertices offset by (X,Y), to ScanLineBuffer, at
double horizontal and vertical resolution */
#define DRAW_POLYGON_DOUBLE_RES(PointList,Color,x,y) \
Polygon.Length = sizeof(PointList)/sizeof(struct Point); \
Polygon.PointPtr = PointTemp; \
/* Double all vertical & horizontal coordinates */ \
for (k=0; k<sizeof(PointList)/sizeof(struct Point); k++) { \
PointTemp[k].X = PointList[k].X * 2; \
PointTemp[k].Y = PointList[k].Y * 2; \
} \
FillCnvxPolyDrvr(&Polygon, Color, x, y, DrawBandedList);
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200
#define SCREEN_SEGMENT 0xA000
#define SCAN_BAND_WIDTH (SCREEN_WIDTH*2) /* # of double-res pixels
across scan band */
#define BUFFER_SIZE (SCREEN_WIDTH*2*2) /* enough space for one scan
line scanned out at double
resolution horz and vert */
void main(void);
void DrawPixel(int, int, char);
int ColorComponent(int, int);
extern int FillCnvxPolyDrvr(struct PointListHeader *, int, int, int,
void (*)());
extern void DrawBandedList(struct HLineList *, int);
/* Pointer to buffer in which double-res scanned data will reside */
unsigned char *ScanLineBuffer;
int ScanBandStart, ScanBandEnd; /* top & bottom of each double-res
band we'll draw to ScanLineBuffer */
int ScanBandWidth = SCAN_BAND_WIDTH; /* # pixels across scan band */
static char Palette[256*3];
void main()
{
int i, j, k;
struct PointListHeader Polygon;
struct Point PointTemp[4];
static struct Point Face0[] =
{{198,138},{211,89},{169,44},{144,89}};
static struct Point Face1[] =
{{153,150},{198,138},{144,89},{105,113}};
static struct Point Face2[] =
{{169,44},{133,73},{105,113},{144,89}};
unsigned char Megapixel;
union REGS regset;
struct SREGS sregs;
if ((ScanLineBuffer = malloc(BUFFER_SIZE)) == NULL) {
printf("Couldn't get memory\n");
exit(0);
}
/* Set the display to VGA mode 13h, 320x200 256-color mode */
regset.x.ax = 0x0013; int86(0x10, ®set, ®set);
/* Stack the palette for the desired megapixel effect, with each
2-bit field representing 1 of 4 double-res pixels in one of four
colors */
for (i=0; i<256; i++) {
Palette[i*3] = ColorComponent(i, 3); /* red component */
Palette[i*3+1] = ColorComponent(i, 2); /* green component */
Palette[i*3+2] = ColorComponent(i, 1); /* blue component */
}
regset.x.ax = 0x1012; /* load palette block BIOS function */
regset.x.bx = 0; /* start with palette register 0 */
regset.x.cx = 256; /* set all 256 palette registers */
regset.x.dx = (unsigned int) Palette;
segread(&sregs);
sregs.es = sregs.ds; /* point ES:DX to Palette */
int86x(0x10, ®set, ®set, &sregs);
/* Scan out the polygons at double resolution one screen scan line
at a time (two double-res scan lines at a time) */
for (i=0; i<SCREEN_HEIGHT; i++) {
/* Set the band dimensions for this pass */
ScanBandEnd = (ScanBandStart = i*2) + 1;
/* Clear the drawing buffer */
memset(ScanLineBuffer, 0, BUFFER_SIZE);
/* Draw the current band of the cube to the scan line buffer */
DRAW_POLYGON_DOUBLE_RES(Face0, 3, 0, 0);
DRAW_POLYGON_DOUBLE_RES(Face1, 2, 0, 0);
DRAW_POLYGON_DOUBLE_RES(Face2, 1, 0, 0);
/* Coalesce the double-res pixels into normal screen pixels
and draw them */
for (j=0; j<SCREEN_WIDTH; j++) {
Megapixel = (ScanLineBuffer[j*2] << 6) +
(ScanLineBuffer[j*2+1] << 4) +
(ScanLineBuffer[j*2+SCAN_BAND_WIDTH] << 2) +
(ScanLineBuffer[j*2+SCAN_BAND_WIDTH+1]);
DrawPixel(j, i, Megapixel);
}
}
getch(); /* wait for a keypress */
/* Return to text mode and exit */
regset.x.ax = 0x0003; /* AL = 3 selects 80x25 text mode */
int86(0x10, ®set, ®set);
}
/* Draws a pixel of color Color at (X,Y) in mode 13h */
void DrawPixel(int X, int Y, char Color)
{
char far *ScreenPtr;
ScreenPtr = (char far *)MK_FP(SCREEN_SEGMENT, Y*SCREEN_WIDTH+X);
*ScreenPtr = Color;
}
/* Returns the gamma-corrected value representing the number of
double-res pixels containing the specified color component in a
megapixel with the specified value */
int ColorComponent(int Value, int Component)
{
/* Palette settings for 0%, 25%, 50%, 75%, and 100% brightness,
assuming a gamma value of 2.3 */
static int GammaTable[] = {0, 34, 47, 56, 63};
int i;
/* Add up the number of double-res pixels of the specified color
in a megapixel of this value */
i = (((Value & 0x03) == Component) ? 1 : 0) +
((((Value >> 2) & 0x03) == Component) ? 1 : 0) +
((((Value >> 4) & 0x03) == Component) ? 1 : 0) +
((((Value >> 6) & 0x03) == Component) ? 1 : 0);
/* Look up brightness of the specified color component in a
megapixel of this value */
return GammaTable[i];
}
[LISTING THREE]
/* Draws pixels from the list of horizontal lines passed in; drawing
takes place only for scan lines between ScanBandStart and
ScanBandEnd, inclusive; drawing goes to ScanLineBuffer, with
the scan line at ScanBandStart mapping to the first scan line in
ScanLineBuffer. Intended for use in unweighted antialiasing,
whereby a polygon is scanned out into a buffer at a multiple of the
screen's resolution, and then the scanned-out info in the buffer is
grouped into megapixels that are mapped to the closest
approximation the screen supports and drawn. Tested with Borland
C++ 2.0 in C mode in the small model */
#include <string.h>
#include <dos.h>
#include "polygon.h"
extern unsigned char *ScanLineBuffer; /* drawing goes here */
extern int ScanBandStart, ScanBandEnd; /* limits of band to draw */
extern int ScanBandWidth; /* # of pixels across scan band */
void DrawBandedList(struct HLineList * HLineListPtr, int Color)
{
struct HLine *HLinePtr;
int Length, Width, YStart = HLineListPtr->YStart;
unsigned char *BufferPtr;
/* Done if fully off the bottom or top of the band */
if (YStart > ScanBandEnd) return;
Length = HLineListPtr->Length;
if ((YStart + Length) <= ScanBandStart) return;
/* Point to the XStart/XEnd descriptor for the first (top)
horizontal line */
HLinePtr = HLineListPtr->HLinePtr;
/* Confine drawing to the specified band */
if (YStart < ScanBandStart) {
/* Skip ahead to the start of the band */
Length -= ScanBandStart - YStart;
HLinePtr += ScanBandStart - YStart;
YStart = ScanBandStart;
}
if (Length > (ScanBandEnd - YStart + 1))
Length = ScanBandEnd - YStart + 1;
/* Point to the start of the first scan line on which to draw */
BufferPtr = ScanLineBuffer + (YStart - ScanBandStart) *
ScanBandWidth;
/* Draw each horizontal line within the band in turn, starting with
the top one and advancing one line each time */
while (Length-- > 0) {
/* Draw the whole horizontal line if it has a positive width */
if ((Width = HLinePtr->XEnd - HLinePtr->XStart + 1) > 0)
memset(BufferPtr + HLinePtr->XStart, Color, Width);
HLinePtr++; /* point to next scan line X info */
BufferPtr += ScanBandWidth; /* point to next scan line start */
}
}
[LISTING FOUR]
/* The changes required to convert the function FillConvexPolygon,
from Listing 1 in the Feb, 1991, column, into FillCnvxPolyDrvr.
FillConvexPolygon was hardwired to call DrawHorizontalLineList to
draw to the display; FillCnvxPolyDrvr is more flexible because it
draws via the driver passed in as the DrawListFunc parameter */
/****** Delete this line ******/
extern void DrawHorizontalLineList(struct HLineList *, int);
/****** Change this... ******/
int FillConvexPolygon(struct PointListHeader * VertexList, int Color,
int XOffset, int YOffset)
/****** ...to this ******/
int FillCnvxPolyDrvr(struct PointListHeader * VertexList, int Color,
int XOffset, int YOffset, void (*DrawListFunc)())
/****** Change this... ******/
DrawHorizontalLineList(&WorkingHLineList, Color);
/****** ...to this ******/
(*DrawListFunc)(&WorkingHLineList, Color);
[LISTING FIVE]
; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs.
; ****************************************************************
; * Revised 6/19/91 to select correct clock; fixes vertical roll *
; * problems on fixed-frequency (IBM 851X-type) monitors. *
; ****************************************************************
; C near-callable as: void Set320x240Mode(void);
; Tested with TASM 2.0.
; Modified from public-domain mode set code by John Bridges.
SC_INDEX equ 03c4h ;Sequence Controller Index
CRTC_INDEX equ 03d4h ;CRT Controller Index
MISC_OUTPUT equ 03c2h ;Miscellaneous Output register
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
.model small
.data
; Index/data pairs for CRT Controller registers that differ between
; mode 13h and mode X.
CRTParms label word
dw 00d06h ;vertical total
dw 03e07h ;overflow (bit 8 of vertical counts)
dw 04109h ;cell height (2 to double-scan)
dw 0ea10h ;v sync start
dw 0ac11h ;v sync end and protect cr0-cr7
dw 0df12h ;vertical displayed
dw 00014h ;turn off dword mode
dw 0e715h ;v blank start
dw 00616h ;v blank end
dw 0e317h ;turn on byte mode
CRT_PARM_LENGTH equ (($-CRTParms)/2)
.code
public _Set320x240Mode
_Set320x240Mode proc near
push bp ;preserve caller's stack frame
push si ;preserve C register vars
push di ; (don't count on BIOS preserving anything)
mov ax,13h ;let the BIOS set standard 256-color
int 10h ; mode (320x200 linear)
mov dx,SC_INDEX
mov ax,0604h
out dx,ax ;disable chain4 mode
mov ax,0100h
out dx,ax ;synchronous reset while setting Misc Output
; for safety, even though clock unchanged
mov dx,MISC_OUTPUT
mov al,0e3h
out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate
mov dx,SC_INDEX
mov ax,0300h
out dx,ax ;undo reset (restart sequencer)
mov dx,CRTC_INDEX ;reprogram the CRT Controller
mov al,11h ;VSync End reg contains register write
out dx,al ; protect bit
inc dx ;CRT Controller Data register
in al,dx ;get current VSync End register setting
and al,7fh ;remove write protect on various
out dx,al ; CRTC registers
dec dx ;CRT Controller Index
cld
mov si,offset CRTParms ;point to CRT parameter table
mov cx,CRT_PARM_LENGTH ;# of table entries
SetCRTParmsLoop:
lodsw ;get the next CRT Index/Data pair
out dx,ax ;set the next CRT Index/Data pair
loop SetCRTParmsLoop
mov dx,SC_INDEX
mov ax,0f02h
out dx,ax ;enable writes to all four planes
mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels
mov es,ax ; at a time
sub di,di ;point ES:DI to display memory
sub ax,ax ;clear to zero-value pixels
mov cx,8000h ;# of words in display memory
rep stosw ;clear all of display memory
pop di ;restore C register vars
pop si
pop bp ;restore caller's stack frame
ret
_Set320x240Mode endp
end